package com.octant.testtcpudp;

import androidx.appcompat.app.AppCompatActivity;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

    private EditText edt_receive_data,edt_send_data;
    private Button btn_tcp_server,btn_tcp_client,btn_udp_server,btn_udp_client,btn_create,btn_send_data,btn_clear_receive_data;
    private TextView tv_socket_message;
    private boolean tcp_server_create = false,tcp_client_create = false,udp_server_create = false,udp_client_create = false;
    private int show_page = 0;

    private TcpServerRunnable tcpServerRunnable;
    private TcpClientRunnable tcpClientRunnable;
    private UdpServerRunnable udpServerRunnable;
    private UdpClientRunnable udpClientRunnable;

    private String tcpServerData = "";
    private String tcpClientData = "";
    private String udpServerData = "";
    private String udpClientData = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();

    }

    private void initViews(){
        edt_receive_data = findViewById(R.id.edt_receive_data);
        edt_receive_data.setMovementMethod(ScrollingMovementMethod.getInstance());
        edt_send_data = findViewById(R.id.edt_send_data);
        edt_send_data.addTextChangedListener(new HexTextWatcher(edt_send_data));
        btn_tcp_server = findViewById(R.id.btn_tcp_server);
        btn_tcp_server.setSelected(true);
        btn_tcp_server.setOnClickListener(this);
        btn_tcp_client = findViewById(R.id.btn_tcp_client);
        btn_tcp_client.setOnClickListener(this);
        btn_udp_server = findViewById(R.id.btn_udp_server);
        btn_udp_server.setOnClickListener(this);
        btn_udp_client = findViewById(R.id.btn_udp_client);
        btn_udp_client.setOnClickListener(this);
        btn_create = findViewById(R.id.btn_create);
        btn_create.setOnClickListener(this);
        tv_socket_message = findViewById(R.id.tv_socket_message);
        btn_send_data = findViewById(R.id.btn_send_data);
        btn_send_data.setOnClickListener(this);
        btn_clear_receive_data = findViewById(R.id.btn_clear_receive_data);
        btn_clear_receive_data.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn_tcp_server:{
                if (show_page == 0){
                    return;
                }
                show_page = 0;
                edt_receive_data.setText(tcpServerData);
                btn_tcp_server.setSelected(true);
                btn_tcp_client.setSelected(false);
                btn_udp_server.setSelected(false);
                btn_udp_client.setSelected(false);
                if (tcp_server_create){
                    btn_create.setText("cancel");
                    tv_socket_message.setText("create server port:"+tcpServerRunnable.getPort());
                }else {
                    btn_create.setText("create");
                    tv_socket_message.setText("");
                }
            }break;
            case R.id.btn_tcp_client:{
                if (show_page == 1){
                    return;
                }
                show_page = 1;
                edt_receive_data.setText(tcpClientData);
                btn_tcp_server.setSelected(false);
                btn_tcp_client.setSelected(true);
                btn_udp_server.setSelected(false);
                btn_udp_client.setSelected(false);
                if (tcp_client_create){
                    btn_create.setText("cancel");
                    tv_socket_message.setText("client connect ip:"+tcpClientRunnable.getServerIp()+";port:"+tcpClientRunnable.getServerPort());
                }else {
                    btn_create.setText("create");
                    tv_socket_message.setText("");
                }
            }break;
            case R.id.btn_udp_server:{
                if (show_page == 2){
                    return;
                }
                show_page = 2;
                edt_receive_data.setText(udpServerData);
                btn_tcp_server.setSelected(false);
                btn_tcp_client.setSelected(false);
                btn_udp_server.setSelected(true);
                btn_udp_client.setSelected(false);
                if (udp_server_create){
                    btn_create.setText("cancel");
                    tv_socket_message.setText("create server port:"+udpServerRunnable.getPort());
                }else {
                    btn_create.setText("create");
                    tv_socket_message.setText("");
                }
            }break;
            case R.id.btn_udp_client:{
                if (show_page == 3){
                    return;
                }
                show_page = 3;
                edt_receive_data.setText(udpClientData);
                btn_tcp_server.setSelected(false);
                btn_tcp_client.setSelected(false);
                btn_udp_server.setSelected(false);
                btn_udp_client.setSelected(true);
                if (udp_client_create){
                    btn_create.setText("cancel");
                    tv_socket_message.setText("client connect ip:"+udpClientRunnable.getServerIp()+";port:"+udpClientRunnable.getServerPort());
                }else {
                    btn_create.setText("create");
                    tv_socket_message.setText("");
                }
            }break;
            case R.id.btn_create:{
                switch (show_page){
                    case 0:{
                        if (!tcp_server_create){
                            showCreateDialog();
                        }else {
                            tcpServerRunnable.close();
                        }
                    }break;
                    case 1:{
                        if (!tcp_client_create){
                            showCreateDialog();
                        }else {
                            tcpClientRunnable.close();
                        }
                    }break;
                    case 2:{
                        if (!udp_server_create){
                            showCreateDialog();
                        }else {
                            udpServerRunnable.close();
                        }
                    }break;
                    case 3:{
                        if (!udp_client_create){
                            showCreateDialog();
                        }else {
                            udpClientRunnable.close();
                        }
                    }break;
                }
            }break;
            case R.id.btn_send_data:{
                switch (show_page){
                    case 0:{
                        if (tcp_server_create) {
                            String text = edt_send_data.getText().toString();
                            if (text.isEmpty()){
                                return;
                            }
                            tcpServerRunnable.sendData(HexUtil.hexToByteArray(text));
                        }
                    }break;
                    case 1:{
                        if (tcp_client_create) {
                            String text = edt_send_data.getText().toString();
                            if (text.isEmpty()){
                                return;
                            }
                            tcpClientRunnable.sendData(HexUtil.hexToByteArray(text));
                        }
                    }break;
                    case 2:{
                        if (udp_server_create) {
                            String text = edt_send_data.getText().toString();
                            if (text.isEmpty()){
                                return;
                            }
                            if (udpServerRunnable.getClientIp().isEmpty()==false) {
                                udpServerRunnable.sendData(HexUtil.hexToByteArray(text), udpServerRunnable.getClientIp(), udpServerRunnable.getClientPort(),cachedThreadPool);
                            }
                        }
                    }break;
                    case 3:{
                        if (udp_client_create) {
                            String text = edt_send_data.getText().toString();
                            if (text.isEmpty()){
                                return;
                            }
                            udpClientRunnable.sendData(HexUtil.hexToByteArray(text),udpClientRunnable.getServerIp(),udpClientRunnable.getServerPort(),cachedThreadPool);
                        }
                    }break;
                }
            }break;
            case R.id.btn_clear_receive_data:{
                edt_receive_data.setText("");
                switch (show_page){
                    case 0:{
                        tcpServerData = "";
                    }break;
                    case 1:{
                        tcpClientData = "";
                    }break;
                    case 2:{
                        udpServerData = "";
                    }break;
                    case 3:{
                        udpClientData = "";
                    }break;
                }
            }break;
        }
    }

    private void showCreateDialog(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Create socket");
        LayoutInflater inflater = LayoutInflater.from(this);
        final View view = inflater.inflate(R.layout.dialog_create_socket,null);
        if (show_page == 0 || show_page == 2){
            LinearLayout ll_ip = view.findViewById(R.id.ll_ip);
            ll_ip.setVisibility(View.GONE);
        }
        builder.setView(view);
        builder.setPositiveButton("Create", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                EditText edt_ip = view.findViewById(R.id.edit_ip);
                EditText edt_port = view.findViewById(R.id.edt_port);
                String ip = edt_ip.getText().toString();
                if (edt_port.getText().toString().isEmpty()){
                    Toast.makeText(getApplicationContext(),"Incorrect PORT format",Toast.LENGTH_SHORT).show();
                    return;
                }
                int port = Integer.parseInt(edt_port.getText().toString());

                switch (show_page){
                    case 0:{
                        tcp_server_create = true;
                        btn_create.setText("Cancel");
                        tcpServerRunnable = new TcpServerRunnable(port);
                        tcpServerRunnable.setListener(tcpServerListener);
                        tv_socket_message.setText("create server port:"+tcpServerRunnable.getPort());
                        cachedThreadPool.execute(tcpServerRunnable);
                    }break;
                    case 1:{
                        if (ip == null || !isCorrectIp(ip)){
                            Toast.makeText(getApplicationContext(),"Incorrect IP format",Toast.LENGTH_SHORT).show();
                            return;
                        }
                        tcp_client_create = true;
                        btn_create.setText("Cancel");
                        tcpClientRunnable = new TcpClientRunnable(ip,port);
                        tcpClientRunnable.setListener(tcpClientListener);
                        tv_socket_message.setText("client connect ip:"+tcpClientRunnable.getServerIp()+";port:"+tcpClientRunnable.getServerPort());
                        cachedThreadPool.execute(tcpClientRunnable);
                    }break;
                    case 2:{
                        udp_server_create = true;
                        btn_create.setText("Cancel");
                        udpServerRunnable = new UdpServerRunnable(port);
                        udpServerRunnable.setListener(udpServerListener);
                        tv_socket_message.setText("create server port:"+udpServerRunnable.getPort());
                        cachedThreadPool.execute(udpServerRunnable);
                    }break;
                    case 3:{
                        if (ip == null || !isCorrectIp(ip)){
                            Toast.makeText(getApplicationContext(),"Incorrect IP format",Toast.LENGTH_SHORT).show();
                            return;
                        }
                        udp_client_create = true;
                        btn_create.setText("Cancel");
                        udpClientRunnable = new UdpClientRunnable(ip,port);
                        udpClientRunnable.setListener(udpClientListener);
                        tv_socket_message.setText("client connect ip:"+udpClientRunnable.getServerIp()+";port:"+udpClientRunnable.getServerPort());
                        cachedThreadPool.execute(udpClientRunnable);
                    }break;
                }
            }
        });
        builder.setNegativeButton("Cancel",null);
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    /** * 判断是否为合法IP **/
    public static boolean isCorrectIp(String ipAddress) {
        String ip = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
        Pattern pattern = Pattern.compile(ip);
        Matcher matcher = pattern.matcher(ipAddress);
        return matcher.matches();
    }

    TcpServerRunnable.TcpServerListener tcpServerListener = new TcpServerRunnable.TcpServerListener() {

        @Override
        public void onTcpServerAcceptClient(final boolean flag, final String clientIp, final int clientPort) {
            if (flag){
                tcpServerData += "client["+clientIp+":"+clientPort+"] connected";
            }else {
                tcpServerData += "client["+clientIp+":"+clientPort+"] disconnected";
            }
            tcpServerData += "\n";
            if (show_page == 0) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        edt_receive_data.setText(tcpServerData);
                    }
                });
            }
        }

        public void onTcpServerReceiveData(final byte[] data, final int len, int port, String clientIp, int clientPort) {
            byte[] tempData = Arrays.copyOf(data,len);
            tcpServerData += HexUtil.bytesToHex(tempData);
            tcpServerData += "\n";
            if (show_page == 0){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        edt_receive_data.setText(tcpServerData);
                    }
                });
            }
        }

        @Override
        public void onTcpServerClose() {
            tcp_server_create = false;
            if (show_page == 0){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        btn_create.setText("Create");
                        tv_socket_message.setText("");
                    }
                });
            }
        }
    };

    TcpClientRunnable.TcpClientListener tcpClientListener = new TcpClientRunnable.TcpClientListener() {
        @Override
        public void onTcpClientConnectServer(boolean flag) {
            if (flag){
                tcpClientData += "connected";
            }else {
                tcpClientData += "disconnected";
            }
            tcpClientData += "\n";
            if (show_page ==1) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        edt_receive_data.setText(tcpClientData);
                    }
                });
            }
        }

        @Override
        public void onTcpClientReceiveData(final byte[] data, final int len, String serverIp, int serverPort) {
            byte[] tempData = Arrays.copyOf(data,len);
            tcpClientData += HexUtil.bytesToHex(tempData);
            tcpClientData += "\n";
            if (show_page == 1){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        edt_receive_data.setText(tcpClientData);
                    }
                });
            }

        }

        @Override
        public void onTcpClientClose() {
            tcp_client_create = false;
            if (show_page == 1){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        btn_create.setText("Create");
                        tv_socket_message.setText("");
                    }
                });
            }
        }
    };

    UdpServerRunnable.UdpServerListener udpServerListener = new UdpServerRunnable.UdpServerListener() {
        @Override
        public void onUdpServerNewConnection(String clientIp, int clientPort) {
            udpServerData += "receive client:["+clientIp+":"+clientPort+"] data";
            udpServerData += "\n";
        }

        @Override
        public void onUdpServerReceiveData(final byte[] data, final int len, int port, String clientIp, int clientPort) {
            byte[] tempData = Arrays.copyOf(data,len);
            udpServerData += HexUtil.bytesToHex(tempData);
            udpServerData += "\n";
            if (show_page == 2){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        edt_receive_data.setText(udpServerData);
                    }
                });
            }
        }

        @Override
        public void onUdpServerClose() {
            udp_server_create = false;
            if (show_page == 2){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        btn_create.setText("Create");
                        tv_socket_message.setText("");
                    }
                });
            }
        }
    };

    UdpClientRunnable.UdpClientListener udpClientListener = new UdpClientRunnable.UdpClientListener() {
        @Override
        public void onUdpClientReceiveNewConnection(String clientIp, int clientPort) {
            udpClientData += "receive from:["+clientIp+":"+clientPort+"] data";
            udpClientData += "\n";
        }

        @Override
        public void onUdpClientReceiveData(final byte[] data, final int len, int port, String serverIp, int serverPort) {
            byte[] tempData = Arrays.copyOf(data,len);
            udpClientData += HexUtil.bytesToHex(tempData);
            udpClientData += "\n";
            if (show_page == 3){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        edt_receive_data.setText(udpClientData);
                    }
                });
            }
        }

        @Override
        public void onUdpClientClose() {
            udp_client_create = false;
            if (show_page == 3){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        btn_create.setText("Create");
                        tv_socket_message.setText("");
                    }
                });
            }
        }
    };
}
